package org.covalence.core.util;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.covalence.core.Observable;

@SuppressWarnings("unchecked")
public class CMap implements Observable, Map {

	private Map _delegate;

	private Observable _parent;

	private String _propertyName; // what his parent names him

	private static Logger log = Logger.getLogger(CMap.class);
	
	public CMap(Object delegate) {
		super();
		this._delegate = (Map) delegate;
	}	
	
	public Object getParent() {
		return this._parent;
	}

	public void setParent(Observable parent) {
		this._parent = parent;		
	}

	public void addNestedObservable(Observable obs, String propertyName) {
		throw new UnsupportedOperationException(
				"Cannot nest observables inside CMap");
	}

	public void addPropertyChangeListener(PropertyChangeListener listener) {
		this._parent.addPropertyChangeListener(listener);
	}

	public void removePropertyChangeListener(PropertyChangeListener listener) {
		this._parent.removePropertyChangeListener(listener);
	}

	public void setNestedPropertyName(String propertyName) {
		this._propertyName = propertyName;
	}

	public void propertyChange(PropertyChangeEvent evt) {}

	public PropertyChangeListener[] getPropertyChangeListeners() { return null; }
	
	public void clear() {
		_delegate.clear();
		_notify();
	}

	public boolean containsKey(Object key) {
		return _delegate.containsKey(key);
	}

	public boolean containsValue(Object value) {
		return _delegate.containsValue(value);
	}

	public Set entrySet() {
		return _delegate.entrySet();
	}

	public boolean equals(Object o) {
		return _delegate.equals(o);
	}

	public Object get(Object key) {
		return _delegate.get(key);
	}

	public int hashCode() {
		return _delegate.hashCode();
	}

	public boolean isEmpty() {
		return _delegate.isEmpty();
	}

	public Set keySet() {
		return _delegate.keySet();
	}

	public Object put(Object key, Object value) {
		Object result = _delegate.put(key, value);
		_notify();
		return result;
	}

	public void putAll(Map t) {
		_delegate.putAll(t);
		_notify();
	}

	public int size() {
		return _delegate.size();
	}

	public Collection values() {
		return _delegate.values();
	}

	public Object remove(Object key) {
		Object result = _delegate.remove(key);
		_notify();
		return result;
	}
	
	private void _notify() {
		if (_propertyName == null) {
			log.warn("Property name was never set, cannot notify.  " +
					"Try nesting this object inside another observable.");
		} else if (_parent == null) {
			log.warn("Parent is null, cannot notify.  " +
					"Make sure the parent property is set.");
		} else {
			_parent.propertyChange(
					new PropertyChangeEvent(_parent, _propertyName, null, this));
		}
	}
}
